// ts_method_bench.cpp — 基于你项目的方法做“取时间戳开销”基准
// Build:
//   g++ -std=c++17 -O2 -pthread -Iinclude src/ts_method_bench.cpp -o tsbench_methods

#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <string>
#include <vector>
#include <unistd.h>
#include <sched.h>

// ===== 关键：使用你自己的方法 =====
#include "time_source.h"     // 需要有 TscSource::now_ns()
#include "logical_clock.h"   // 你给出的 LogicalClock

struct BenchStats {
  uint64_t n = 0;
  double min = 0, mean = 0, median = 0, p95 = 0, p99 = 0, max = 0, stddev = 0;
};

struct Options {
  int   warmup      = 100000;           // 预热次数
  int   samples     = 1000000;          // 采样次数
  bool  pin_cpu0    = true;             // 绑到 CPU0
  bool  csv         = true;             // 写 CSV
  const char* csv_path = "ts_overhead_methods.csv";
  bool  also_print  = true;             // 打印
};

static void pin_cpu0_if_needed(bool pin_cpu0, bool verbose) {
  if (!pin_cpu0) return;
  cpu_set_t set; CPU_ZERO(&set); CPU_SET(0, &set);
  if (sched_setaffinity(0, sizeof(set), &set) != 0 && verbose)
    perror("sched_setaffinity");
}

template<typename Fn>
static BenchStats run_one(const char* tag, Fn read_counter, const Options& opt) {
  // 1) 预热
  for (int i = 0; i < opt.warmup; ++i) { asm volatile(""); }

  // 2) 采样（成对差分法：b-a 近似一次读取成本）
  std::vector<uint64_t> diffs;
  diffs.reserve(opt.samples);
  for (int i = 0; i < opt.samples; ++i) {
    uint64_t a = (uint64_t)read_counter();
    uint64_t b = (uint64_t)read_counter();
    diffs.push_back(b >= a ? (b - a) : 0);
  }

  // 3) 统计
  BenchStats st{};
  if (!diffs.empty()) {
    st.n = diffs.size();
    std::sort(diffs.begin(), diffs.end());
    auto q = [&](double p) -> double {
      size_t idx = (size_t)std::floor(p * (diffs.size() - 1) + 0.5);
      if (idx >= diffs.size()) idx = diffs.size() - 1;
      return (double)diffs[idx];
    };
    st.min    = (double)diffs.front();
    st.max    = (double)diffs.back();
    st.median = q(0.5);
    st.p95    = q(0.95);
    st.p99    = q(0.99);
    long double sum = 0;
    for (auto x : diffs) sum += x;
    st.mean = (double)(sum / (long double)diffs.size());
    long double ss = 0;
    for (auto x : diffs) {
      long double d = (long double)x - st.mean;
      ss += d * d;
    }
    st.stddev = (double)std::sqrt(ss / (long double)diffs.size());
  }

  // 4) 打印（单位：ns）
  if (opt.also_print) {
    std::printf("\n[%s]\n", tag);
    std::printf("  unit: ns\n");
    std::printf("  stats: n=%llu, min=%.0f ns, p50=%.0f ns, mean=%.2f ns, p95=%.0f ns, p99=%.0f ns, max=%.0f ns, std=%.2f ns\n",
      (unsigned long long)st.n, st.min, st.median, st.mean, st.p95, st.p99, st.max, st.stddev);
  }

  // 5) CSV
  if (opt.csv) {
    bool new_file = (access(opt.csv_path, F_OK) != 0);
    FILE* fp = std::fopen(opt.csv_path, "a");
    if (fp) {
      if (new_file) {
        std::fprintf(fp, "tag,unit,n,min,median,mean,p95,p99,max,stddev\n");
      }
      std::fprintf(fp, "%s,%s,%llu,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f\n",
                   tag, "ns", (unsigned long long)st.n,
                   st.min, st.median, st.mean, st.p95, st.p99, st.max, st.stddev);
      std::fclose(fp);
    } else if (opt.also_print) {
      perror("fopen csv");
    }
  }

  return st;
}

int main(int argc, char** argv) {
  Options opt; // 仍用默认：warmup=1e5, samples=1e6, 绑核、写CSV并打印

  // 先做一次 TSC 频率校准（比如 0.3s，窗口稍长更稳）
  auto cal = TscSource::init(0.3);
  if (!cal.ok) {
    std::fprintf(stderr,
      "[FATAL] TSC 未就绪（无 invariant TSC 或校准失败）。"
      "请在支持 invariant TSC 的机器上运行，或在 time_source 中加入回退路径。\n");
    return 1;
  }
  if (opt.also_print) {
    std::printf("[Init] TSC frequency ≈ %.3f GHz\n", TscSource::ghz());
  }

  // 绑核，减少迁核抖动
  pin_cpu0_if_needed(opt.pin_cpu0, opt.also_print);

  // ====== 1) 测你的 TscSource::now_ns() ======
  auto tsc_reader = []() -> uint64_t {
    return static_cast<uint64_t>(TscSource::now_ns());
  };
  run_one("TscSource::now_ns", tsc_reader, opt);

  // ====== 2) 测你的 LogicalClock::now_ns()（偏移为 0） ======
  LogicalClock lc(0);
  auto logic_reader = [&lc]() -> uint64_t {
    return static_cast<uint64_t>(lc.now_ns());
  };
  run_one("LogicalClock::now_ns", logic_reader, opt);

  if (opt.also_print) {
    std::puts("\n结果已写入 ts_overhead_methods.csv（单位 ns）。");
  }
  return 0;
}